home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume3 / help < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  26.3 KB

  1. From: wucs!nz (Neal Ziring)
  2. Subject: help: VMS-style help facility
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 29
  7. Submitted by: seismo!wucs!nz (Neal Ziring)
  8.  
  9.  
  10. Here is our VMS-style help utility.
  11.  
  12. ...nz (Neal Ziring @ the American Midwest)
  13. -----------------------------------------------------
  14. #! /bin/sh
  15. # This is a shell archive, meaning:
  16. # 1. Remove everything above the #! /bin/sh line.
  17. # 2. Save the resulting text in a file.
  18. # 3. Execute the file with /bin/sh (not csh) to create the files:
  19. #    help/Makefile
  20. #    help/README
  21. #    help/help.1
  22. #    help/help.h
  23. #    help/help.c
  24. # This archive created: Mon Oct 28 10:21:23 1985
  25. if test -d 'help'
  26. then
  27.     echo shar: directory "'help'" already exists
  28. else
  29.     mkdir 'help'
  30. fi # end of directory check
  31. export PATH; PATH=/bin:$PATH
  32. if test -f 'help/Makefile'
  33. then
  34.     echo shar: will not over-write existing file "'help/Makefile'"
  35. else
  36. cat << \SHAR_EOF > 'help/Makefile'
  37. #
  38. #  help Makefile, 1.1    7/27/84
  39. #
  40. CFLAGS= -g
  41. DESTDIR=
  42.  
  43. help:    help.o 
  44.     ${CC} ${CFLAGS} help.o -o help
  45.  
  46. install: help
  47.     install -s -c help $(DESTDIR)/usr/local/bin
  48.  
  49. help.o: help.h /usr/include/sys/file.h /usr/include/sys/param.h
  50.  
  51. clean:  
  52.     rm -f *.o help
  53.  
  54. SHAR_EOF
  55. fi # end of overwriting check
  56. if test -f 'help/README'
  57. then
  58.     echo shar: will not over-write existing file "'help/README'"
  59. else
  60. cat << \SHAR_EOF > 'help/README'
  61.  
  62.  Help is a facility for climbing a tree structure.
  63.  
  64.  Help comes in two types: a help topic with subtopics, or a help topic
  65.  without any subtopics.  
  66.  
  67.     Topics that have no subtopics reside in the directory they are
  68.     a subtopic of, with filenames `topicname.HLP'
  69.  
  70.     Topics that have subtopics of their own reside in directories
  71.     which are subdirectories of the help topic of which they are
  72.     subtopics, and have filenames `.HLP'  Thier subtopics have the
  73.     filenames `topicname.HLP'.  A directory for a subtopic just
  74.     has the subtopic's name as its directory name.
  75.  
  76.     For instance, if you had a help topic "ls" with some subtopics,
  77.     /usr/help/ls would be a directory, containing the files
  78.  
  79.         /usr/help/ls/.HLP    main help text
  80.         /usr/help/ls/.MANUAL    shell script for accessing man page
  81.         /usr/help/ls/options.HLP    help for ls options
  82.         /usr/help/ls/output.HLP        help for ls output format
  83.  
  84.     If you had a simple help for the who command, "who", it would comprise
  85.     the following files at the top level:
  86.  
  87.         /usr/help/who.HLP    help text for who(1)
  88.         /usr/help/who.MANUAL    script for accessing who(1) man page
  89.  
  90. To make help, cd to the directory, and type: 
  91.  
  92.     % make help
  93.  
  94. or
  95.  
  96.     % make install
  97.  
  98. if you are ambitious.  The source for help is one C module, help.c, with a 
  99. header file, help.h.
  100.  
  101. Help uses the more(1) program to read help texts.  Make sure that more
  102. resides on the path specified by the VIEWPROGRAM defined symbol in help.h.
  103.  
  104. SHAR_EOF
  105. fi # end of overwriting check
  106. if test -f 'help/help.1'
  107. then
  108.     echo shar: will not over-write existing file "'help/help.1'"
  109. else
  110. cat << \SHAR_EOF > 'help/help.1'
  111. .TH HELP 1 "29 November 1984"
  112. .UC 4
  113. .SH NAME
  114. help \- user-friendly documentation reader
  115. .SH SYNOPSIS
  116. .B help
  117. [ -dlqCn ] [ topic-path ]
  118. .br
  119. .SH DESCRIPTION
  120. .I Help
  121. is a documentation reader based closely on the VMS(tm) help facility.
  122. Documentation texts are arranged in a tree, and the users reads them with
  123. .I more(1).
  124. Help allows documentation to be treated as an n-tree, the
  125. structure of the help tree is the structure of the directory tree in
  126. which the help files reside.
  127. .PP
  128. The help program is invoked from the shell like
  129. .PP
  130.     help  [ -dlqCn ] topic sub-topic sub-sub-topic ...
  131. .PP
  132. .I Topic
  133. may be any top-level help file name.  A 
  134. .I topic-path
  135. is a path of topics and their subtopics, down into the tree.
  136. Topic and subtopic names may be abbreviated, but no wild-cards
  137. are recognized.
  138. If any switches are present they all must follow a single dash,
  139. and be the first option on the command line.
  140. .PP
  141. The options are:
  142. .TP 5
  143. .B d
  144. Next argument is the help root directory.  Default is /usr/help.
  145. .TP 5
  146. .B l
  147. Use list-only mode.  Only the list of subtopics for the command-line
  148. help path is printed.  Interactive mode is not used.
  149. .TP 5
  150. .B q
  151. Use text-only mode.  Only the text of the help path is printed.
  152. Interactive
  153. mode is not used.
  154. .TP 5
  155. .B C
  156. Forces multi-column output of subtopic lists.
  157. This is the default for interactive mode.
  158. .TP 5
  159. .B n
  160. Force one-topic-per-line output of the subtopics lists.
  161. This is the default for list mode.
  162. .PP
  163. The help interactive mode asks the user what help he would like next.
  164. The prompt looks like this:
  165. .PP
  166. Topic?
  167. .PP
  168. or like this:
  169. .PP
  170. vi commands deletion subtopic?
  171. .PP
  172. Where "vi commands deletion" is the 
  173. .I "help tree path."
  174. This path is printed for each prompt, and as a header for each help
  175. text.
  176. .PP
  177. The following commands are meaningful in to the "topic?" prompt:
  178. .TP 5
  179. .B ?
  180. Print current help and subtopic-list again.
  181. .TP 5
  182. .B ".<topic-name>"
  183. Do a UNIX Programmer's Manual lookup (if possible).  If other characters
  184. follow the dot, they are taken as the filename for the .MANUAL file.
  185. (e.g. command '.who' looks for file who.MANUAL)
  186. .TP 5
  187. .B "Return <CR>"
  188. Exit this level of help.  If at top level, goes back to calling
  189. program.
  190. .TP 5
  191. .B "<subtopic-name>"
  192. Read the documentation for this subtopic, or all subtopics for which
  193. this is a legal abbreviation.  Wildcards are not permitted, but a
  194. short abbreviation matches everything longer.
  195. .TP 5
  196. .B "#"
  197. List the available subtopics again.  This lists the subtopics of this
  198. node, and re-prompts the user.  The help text is NOT re-printed.
  199. .TP 5
  200. .B "$<topicname>"
  201. List some information on the files that make up this topic.  Files
  202. that match the abbreviation of `topicname' are looked up with 
  203. .I file(1).
  204. .sp 1
  205. .PP
  206. .B "HELP FILES"
  207. .PP
  208. Help files are the text and directories of the 
  209. .I help
  210. documentation tree.
  211. There are four kinds of help files: topic directory, help file,
  212. subtopic file, and manual file.
  213. .PP
  214. A topic directory is a directory with the name of the subtopic it
  215. describes (e.g.  /usr/help/ls/options is a topic directory about the
  216. topic of options for 
  217. .I ls(1)).
  218. .PP
  219. A help file is a file of formatted text with the name ".HLP".  It
  220. resides in the topic directory for which it is the description text.
  221. .PP
  222. A subtopic file has the name  "subtopic-name.HLP".  It contains the
  223. text for a subtopic which does not itself have any subtopics.
  224. .PP
  225. A manual file contains the commands to be given to 
  226. .I sh(1)
  227. when the user gives the lookup manual command (.).
  228. This file has name <topic>.MANUAL.  Therefore the manual command
  229. script for the current node is just ".MANUAL".
  230. .br
  231. A manual file resides in the same topic directory as the help text 
  232. whose corresponding
  233. manual it accesses.  
  234. The manual may be a shell script or a binary file, but it must be marked
  235. executable by all users.
  236. .sp 1
  237. .PP
  238. The usual way of calling help is to just type 
  239. .sp 1
  240. %
  241. .I help
  242. .PP
  243. in the shell.  This brings up help interactive mode at the top level
  244. of topics.  The user can always abort with ctrl/D.
  245. .SH AUTHOR
  246. Neal Ziring with George Robbert, Washington University in St. Louis.
  247. .SH FILES
  248. /usr/local/bin/help
  249. .br
  250. /usr/help*
  251. .br
  252. /usr/ucb/more
  253. .br
  254. /bin/sh
  255. .SH "SEE ALSO"
  256. more(1), man(1), sh(1), system(2), access(2)
  257. .SH DIAGNOSTICS
  258. Error messages are printed whenever a request is made to get
  259. documentation that does not exists, or is not accessible.  
  260. .PP
  261. Signals are not trapped.
  262. .SH BUGS
  263. The file naming conventions are somewhat strict.
  264. .PP
  265. No wildcards allowed in topic names.  (Could have made them reg. exp.
  266. but that would be confusing to novices.)
  267. .PP
  268. Terminal type is not checked, the display is assumed to be at least 76
  269. columns wide.
  270. .PP
  271. There is no way for the user to specify another program for viewing
  272. files ("more -d" is always used.)  This is coded into the header file.
  273. .PP
  274. The algorithm used for selecting amoung ambiguous help paths is
  275. non-obvious, and can be confusing when too-short abbreviations are used.
  276.  
  277. SHAR_EOF
  278. fi # end of overwriting check
  279. if test -f 'help/help.h'
  280. then
  281.     echo shar: will not over-write existing file "'help/help.h'"
  282. else
  283. cat << \SHAR_EOF > 'help/help.h'
  284.  
  285.     /*
  286.          *    help.h: header file for the VMS-help emulator
  287.      */
  288.  
  289. #include <stdio.h>
  290. #include <ctype.h>
  291. #include <sys/file.h>
  292. #include <sys/param.h>
  293. #include <sys/dir.h>
  294.  
  295.  
  296. #define iswhite(_c)       (_c ==' ' || _c =='    ' || _c =='\n' || _c =='\r')
  297. #define PROMPT " Topic? "
  298. #define SUBPROMPT "subtopic? "
  299. #define HELPEX    ".HLP"                /* help extension */
  300. #define    MANEX    ".MANUAL"            /* manual filename*/
  301. #define MAN_SUBEX "/.MANUAL"                    /* other man filename */
  302. #define INFOHEAD "file "
  303. #define INFOTAIL " | sed 's/^/     /'"
  304.  
  305. #define    MAXLINELEN    128
  306. #define    MAXNAMELEN     20        /* max length of NAME of topix */
  307. #define    MAXNAMES    256        /* maximum number of subtopics */
  308. #define COLUMNSPACE      4
  309. #define TERMWID         76
  310. #define HELPDIR "/usr/help"
  311. #define VIEWPROGRAM  "/usr/ucb/more"    /* program to look at text */
  312. #define VIEWPROGOPTS1 "-d"
  313. #define VIEWPROGOPTS2 "-18"
  314. #define SHELLPROG    "/bin/sh"        /* program to execute text */
  315. #define SHELLOPTS    "-c"
  316.  
  317. char     progname[MAXNAMELEN];
  318. char    olddir[MAXNAMELEN + 68];
  319. char    newdir[MAXNAMELEN + 68];
  320. char    *helpdir;
  321. char    **environ;    /* environment, for forks */
  322.  
  323. int    dumb_flag;
  324. int    list_flag;
  325. int    col_flag;
  326. int    frst_flag;
  327.  
  328. char    *helpcmds[] =
  329.     { "Return - Exit this level of help",
  330.       "*      - Print this message",
  331.       "?      - Reprint this help and its subtopics",
  332.       "#      - Reprint just subtopics of this help",
  333.       ".      - Look at current manual page, if any",
  334.       "$<topic>    - Get information on topic files",
  335.       ".<topic>    - Look at topic manual page, if any",
  336.       "<topic>     - Look at help for subtopic `topic'" ,
  337.       NULL
  338.     };
  339.  
  340. SHAR_EOF
  341. fi # end of overwriting check
  342. if test -f 'help/help.c'
  343. then
  344.     echo shar: will not over-write existing file "'help/help.c'"
  345. else
  346. cat << \SHAR_EOF > 'help/help.c'
  347. #include "help.h"
  348. #define MAXMATCHES    24
  349.  
  350.  /* ************************************************************
  351.   *             H   E   L   P    !!
  352.   *             =========================
  353.   *
  354.   *     This program emulates the VMS help facility in the UNIX
  355.   *  environment.  The main routine HELP1 looks up help and 
  356.   *  subtopics for help.  The help texts for various topix 
  357.   *  are tree-structured.  A directory is defined as a "help"
  358.   *  directory, it has four types of files in it:
  359.   *        main help text:     .HLP
  360.   *        manual page name:    .MANUAL
  361.   *        subtopic texts:        <topicname>.HLP
  362.   *        subtopic directories:    <topicname>
  363.   *
  364.   *    Subtopic names must start with an alphanumeric
  365.   *  character.  Preferably all subtopics will start with
  366.   *  lowercase letters.
  367.   *
  368.   *    The routine help1 is recursive, it descends the    tree
  369.   *  structure.
  370.   */
  371.  
  372.   main(argc, argv)
  373.       int argc;
  374.     char *argv[];
  375.   {
  376.     int i,j,k;
  377.     int longlen;
  378.     char yesno[10];
  379.     char *opts;
  380.         
  381.     strcpy(progname,argv[0]);
  382.     helpdir = NULL;
  383.     getwd(olddir);
  384.     dumb_flag = 0;
  385.     list_flag = 0;
  386.     frst_flag = 1;
  387.     col_flag  = 1;
  388.  
  389.     argc--;
  390.     if (*(*++argv) == '-') {        /* must be options */
  391.         for (opts = *argv; *opts != '\0'; opts++) {
  392.             switch(*opts) {
  393.                case '-' :    
  394.                    break;
  395.  
  396.                case 'd' :    
  397.                    if (argc > 1) {
  398.                     helpdir = *++argv;
  399.                     argc--;
  400.                 }
  401.                 break;
  402.  
  403.                case 'l' :
  404.                    list_flag = 1;
  405.                 col_flag = 0;
  406.                 break;
  407.  
  408.                case 'q' :
  409.                    dumb_flag = 1;
  410.                 break;
  411.  
  412.                case 'C' :
  413.                    col_flag = 1;
  414.                 break;
  415.  
  416.                case 'n' :
  417.                    col_flag = 0;
  418.  
  419.                default:
  420.                     fprintf(stderr,"%s: %c: bad option.\n",
  421.                     progname,*opts);
  422.                 break;
  423.             }
  424.         }
  425.         argc--; argv++;
  426.     }
  427.  
  428.     if (helpdir == NULL) helpdir = HELPDIR;
  429.  
  430.     if (chdir(helpdir) < 0) {
  431.         fprintf(stderr,"%s: %s: help directory not found.\n",
  432.             progname,helpdir);
  433.         exit(1);
  434.     }
  435.  
  436.     if (argc >= 1) {        /* treat vector as a help path */
  437. #ifdef DEBUG
  438.         fprintf(stderr," help path vector, argc=%d, *argv=%s.\n",
  439.             argc,*argv);
  440. #endif
  441.         help1( "", argv, 0);
  442.  
  443.     }
  444.     else    help1( "", NULL, 0);
  445.  
  446.     exit(0);
  447.  }
  448.  
  449.  
  450.  
  451.  
  452.  /* **************************************************************
  453.   * printhelp: given a string, pop .HLP on the end on do 
  454.   *    a more on it.
  455.   *
  456.   *    This routine sends a help file to more(1).  A string
  457.   *  is passed in, which is the name of a help.  If the string
  458.   *  is nil, then just use the name HLP.
  459.   *    The return value is -1 if no help file is accessible, 
  460.   *  0 if the more(1) command was called okay with fkoff();
  461.   */
  462.  
  463.   printhelp(hs, path)
  464.       char *hs;
  465.   {
  466.     char filename[MAXNAMELEN], comm[MAXNAMELEN + 20];
  467.  
  468.     if (hs == NULL) strcpy(filename,HELPEX);
  469.     else if (strlen(hs) < 1) strcpy(filename, HELPEX);
  470.     else {
  471.         strcpy(filename, hs);
  472.         strcat(filename,HELPEX);
  473.     }
  474.  
  475.     if ( access(filename, R_OK) < 0 ) {
  476.         printf("\n Sorry, no help text for %s.\n",
  477.             (hs==NULL)?"this topic":hs );
  478.         return(-1);
  479.     }
  480.  
  481.     if (path != NULL) printf("\n HELP: %s\n",path);
  482.  
  483.     fkoff(VIEWPROGRAM,VIEWPROGOPTS1,VIEWPROGOPTS2,filename,NULL);
  484.  
  485.     return(0);
  486.   }
  487.  
  488.  
  489.  
  490. /* *************************************************************
  491.  * printtopix: print the topics available in this directory
  492.  *        in a nice format.
  493.  *
  494.  *    This routine does a directory of help options, 
  495.  *  and prints them out in a manner similar to that of ls(1).
  496.  *  All filenames which start with anything other than numbers 
  497.  *  or letters are not kept.  Extensions are stripped off.
  498.  *    
  499.  *    The number of subtopics found is returned, along with
  500.  *  a pointer to a null-terminated vector of string pointers.
  501.  *  If the mode is non-zero, it means just use the strings stored
  502.  *  in topix.  If mode==0, then re-allocate space and re-check
  503.  *  the directory.  If mode
  504.  */
  505.  
  506.  printtopix( topix, mode, supress)
  507.      char *topix[];
  508.     int mode, supress;
  509.  {
  510.     int i,j,k,l;
  511.     int longlen;
  512.     int  namewidth, totalnames, rowcnt, colcnt;
  513.     char *malloc(), *nbuf;
  514.     char row[TERMWID+1];
  515.     char *thisname, *index();
  516.     char *s1, *s2, **nxtname, *nxcnt;
  517.     struct direct *readdir(), *filedat;
  518.     DIR *dirp, *opendir();
  519.  
  520.     if ( mode ) {
  521.         for(nxtname=topix, i=0; *nxtname++ != NULL; i++ );
  522.         totalnames = i;
  523.         goto inputtopix;
  524.     }
  525.  
  526.     /* if mode is zero, then allocate space and search the directory */
  527.     nbuf = malloc( MAXNAMES * MAXNAMELEN );
  528.     nxcnt=nbuf;
  529.     dirp = opendir(".");
  530.     if (dirp == NULL) {
  531.         fprintf(stderr,"%s: Cannot open help directory.\n",progname);
  532.         return(-1);
  533.     }
  534.  
  535.     for(nxtname=topix, i=0; i < (MAXNAMES-1) ; ) {
  536.         filedat = readdir(dirp);
  537.         if (filedat == NULL) break;
  538.         thisname = filedat->d_name;
  539.         if ( !(isalnum(*thisname)) )    /* if not in [0-9A-Za-z] */
  540.                 continue;    /* do the next one.      */
  541.         if ( (s1 = index(thisname,'.')) != NULL) {
  542.             if (strcmp(s1, HELPEX) == 0) *s1 = '\0';
  543.             else if ( strcmp(s1, MANEX) == 0) continue;
  544.         }
  545.         if (strlen(thisname) >= MAXNAMELEN)
  546.             *(thisname+MAXNAMELEN-1) = '\0';
  547.         /* copy in data from this loop */
  548.         strcpy(nxcnt,thisname);
  549.         *nxtname++ = nxcnt; 
  550.         /* update pointers for next loop */
  551.         nxcnt += strlen(thisname) + 1;
  552.         i++;
  553.     }
  554.     *nxtname++ = NULL;
  555.     totalnames = i;
  556.     closedir(dirp);
  557.  
  558.     if (totalnames == 0) return(0);
  559.     
  560.     /* sort the names in ascending order with exchange algorithm */
  561.     for(i=0; i < totalnames-1; i++)
  562.         for(j=i+1; j <totalnames; j++)
  563.             if (strcmp(topix[i],topix[j]) > 0) {
  564.                 thisname = topix[i];
  565.                 topix[i] = topix[j];
  566.                 topix[j] = thisname;
  567.             }
  568.  
  569.  inputtopix:
  570.     if (supress) return(totalnames);
  571.  
  572.     longlen = 0;
  573.     for(i=0; i < totalnames; i++ )
  574.         longlen = ((k=strlen(topix[i]))>longlen)?k:longlen;
  575.  
  576.     /* here print the names out in nice columns */
  577.     namewidth = longlen + COLUMNSPACE;
  578.     rowcnt = TERMWID / namewidth;
  579.     colcnt = (totalnames + (rowcnt-1)) / rowcnt ;
  580.     if (colcnt <= 0) colcnt = 1;
  581.  
  582.     if (col_flag && rowcnt > 1) {
  583.         printf("\n Subtopics:\n\n");
  584.         for(i=0; i < colcnt ; i++ ) {
  585.             for(k=0; k < TERMWID; row[k++] = ' ');
  586.             row[k] = '\0';
  587.             for(j=0, s1 = row; 
  588.                     (i+j) < totalnames; 
  589.                     j += colcnt) {
  590.                 row[strlen(row)] = ' ';
  591.                 strcpy(s1,topix[i+j]);
  592.                 s1 = s1 + namewidth;
  593.             }
  594.             printf("    %s\n",row);
  595.         }
  596.         printf("\n");
  597.     }
  598.     else {
  599.         for(i=0; i < totalnames; i++)
  600.             printf("%s\n",topix[i]);
  601.      }
  602.  
  603.     return(totalnames);
  604.  }
  605.  
  606.  
  607.  
  608.  /* ****************************************************************
  609.   * help1: descend recursive help tree and provide some
  610.   *         user services.
  611.   *
  612.   *    This routine is the heart of the new UNIX help facility.
  613.   *  It climbs recursively around an n-tree of documentation files
  614.   *  and directories.  The routine printhelp() outputs a file of
  615.   *  help text, the routine printtopix prints out all subtopics.
  616.   *
  617.   *    This routine can operate in interactive mode, or not.  The
  618.   *  basic cycle of operation is:
  619.   *        if (not list-only-mode) print help.
  620.   *        if (not quiet-mode)    print list.
  621.   *        if (not interactive)    return.
  622.   *        print prompt and do commands.
  623.   *        return.
  624.   *
  625.   *    There are a number of commands available in the
  626.   *  interactive mode, they are:
  627.   *
  628.   *        blank line:    up recursive level.
  629.   *        subtopic name:    recurse to subtopic.
  630.   *        ?:        list topics again.
  631.   *        *:        get list of commands
  632.   *        $:        get info on topix
  633.   *        ^D:        quit help program.
  634.   *        .:        man page (if any).
  635.   *        #        list topics again
  636.   *        
  637.   */
  638.  
  639.   help1(ppt,svec,skip)
  640.       char *ppt;                /* prompt */
  641.     char *svec[];
  642.     int  skip;
  643.  
  644.   {
  645.  
  646.     int i,j,k, err;
  647.     int no_subs;
  648.     char answer[MAXLINELEN];
  649.     char fullpath[MAXNAMELEN + 11];
  650.     char yesno[10];
  651.     char *topix[MAXNAMES], *mx[MAXMATCHES];
  652.     int  matchv();
  653.     char *index(), *getenv();
  654.     char *s1, *s2, *s3, *rest;
  655.     char *wvec[MAXMATCHES];
  656.     char cmdbuf[90];
  657.  
  658.     if ( svec != NULL  && *svec != NULL) {
  659.         printtopix( topix, 0, 1);
  660.         if ( (k = matchv(*svec, topix, mx)) == 0) {
  661.         printf(" sorry, no help path to %s %s\n\n",ppt,*svec);
  662.         return(-1);
  663.         }
  664.         for(i=0, err = -1; mx[i] != NULL; ) {
  665.         if (i > 0)
  666.           j = takeit(" Next help path: %s %s\nTry it?",ppt,mx[i]);
  667.         if (j == 1) { i++; continue; }
  668.         if (j < 0)  break;
  669.         strcpy(fullpath,ppt);
  670.         strcat(fullpath," ");
  671.         strcat(fullpath,mx[i]);
  672.         if ( chdir(mx[i]) < 0) {
  673.             if ( *(svec + 1) != NULL ) {
  674.             i++;
  675.             continue;
  676.             }
  677.             if (list_flag) 
  678.             return(-1);
  679.             else
  680.             printhelp( mx[i],fullpath);
  681.             printf("\n");
  682.             if (!dumb_flag) help1(ppt,NULL,1);
  683.             err = 0;
  684.         }
  685.         else {
  686.             if ( help1(fullpath,(svec+1),0) >= 0) {
  687.             err = 0;
  688.             chdir("..");
  689.             printf("\n");
  690.             if (!dumb_flag) help1(ppt,NULL,1);
  691.             }
  692.             else chdir("..");
  693.         }
  694.         i++;
  695.         }
  696.         return(err);
  697.     }
  698.  
  699.     if ( !list_flag && !skip) 
  700.         if (printhelp(NULL, ppt) < 0) {
  701.         return(-1);
  702.         }
  703.  
  704.     if ( !list_flag && !dumb_flag && ( access(MANEX, R_OK) >= 0) && !skip)
  705.         printf("\n    Manual page IS available.\n");
  706.  
  707.     if ( !dumb_flag ) {
  708.         if ( printtopix( topix, 0, skip) <= 0 ) {
  709.         no_subs = 1;
  710.         }
  711.         else no_subs= 0;
  712.     }
  713.  
  714.     if ( dumb_flag  ||  list_flag ) return(0);
  715.  
  716.     while ( 1 ) {
  717.         if (frst_flag) {
  718.             printf(" (type '*' for commands)\n");
  719.             frst_flag = 0;
  720.         }
  721.         if ( strlen(ppt) < 1 ) printf("%s",PROMPT);
  722.         else         printf("  %s %s",ppt,SUBPROMPT);
  723.         if ( fgets(answer, MAXLINELEN-1, stdin) == NULL ) {
  724.             printf("\nbye...\n");
  725.             exit(1);
  726.         }
  727.  
  728.         /* first remove any leading blanks or tabs */
  729.         for(s1=answer; *s1 == ' ' || *s1 == '    '; s1++);
  730.  
  731.         /* chop off all of answer after first word. */
  732.         s2 = index(s1, ' ');
  733.         if (s2 == 0) s2 = index(s1, '\n');
  734.         if (s2) { *s2 = '\0'; rest = s2+1; }
  735.         else rest = s1 + (strlen(s1) - 1);
  736.         makewvec(rest,wvec);
  737.  
  738.         if ( strlen(s1) == 0 )        /*  on blank line, */
  739.             break;            /* pop up one level*/
  740.  
  741.         switch (*s1) {
  742.                 case '?':            /* ?: print stuff again */
  743.                 printhelp(NULL, ppt);
  744.             if ( access(MANEX, R_OK) >= 0 )
  745.                 printf("\n    Manual page IS available.\n");
  746.                 if (!no_subs) printtopix(topix, 1,0);
  747.             else    printf("\n Sorry, no subtopics.\n\n");
  748.             break;
  749.  
  750.             case '#':
  751.             if (!no_subs) printtopix( topix, 1,0);
  752.             else    printf("\n Sorry, no subtopics.\n\n");
  753.             break;
  754.  
  755.             case '*':            /* *: list commands */
  756.             printf("\n");
  757.                 for(i=0; helpcmds[i] != NULL; i++) {
  758.                 printf("    %s\n",helpcmds[i]);
  759.             }
  760.             printf("\n");
  761.             break;
  762.  
  763.             case '$':            /* $: find out about files */
  764.                 s2 = s1 + 1;
  765.             if (no_subs) {
  766.                 printf("\n Sorry, no subtopics.\n\n");
  767.                     break;
  768.             }
  769.             strcpy(cmdbuf, INFOHEAD);
  770.             strcat(cmdbuf,s2);
  771.             strcat(cmdbuf,"* ");
  772.             strcat(cmdbuf, INFOTAIL);
  773.             printf("\n File information: \n");
  774.             system(cmdbuf);
  775.             printf("\n");
  776.             break;
  777.                 
  778.  
  779.                 case '.':            /* .: do manpage if any */
  780.                 s2 = s1 + 1;
  781.             if (no_subs) {
  782.                 printf("\n Sorry, no subtopics.\n\n");
  783.                     break;
  784.             }
  785.             if ( *s2 == '\0' ) {
  786.                 mx[0] = "";  mx[1] = NULL; k = 1;
  787.             }
  788.             else if ( (k = matchv( s2, topix, mx)) == 0 ) {
  789.                printf("\n Sorry, no topics match %s\n",s2);
  790.                printf(" (list cmnds with '*', topix with '#')\n");
  791.             }
  792.             for( i=0; i < k; i++ ) {
  793.                 strcpy(cmdbuf,mx[i]);
  794.                 strcat(cmdbuf,MANEX);
  795.                 if (access(cmdbuf, R_OK|X_OK ) < 0) {
  796.                         strcpy(cmdbuf,mx[i]);
  797.                     strcat(cmdbuf,MAN_SUBEX);
  798.                     if (access(cmdbuf,R_OK|X_OK) < 0) {
  799.                         printf("\n Sorry, %s for %s.\n\n",
  800.                           "No manual reference available",
  801.                           (strlen(s2)==0)?ppt:mx[i]);
  802.                         continue;
  803.                     }
  804.                 }
  805.                 if (i > 0) {
  806.                       k=
  807.                      takeit(" Next man page: %s.\n Take it? ",
  808.                     mx[i]);
  809.                      if (k ==  1) continue;
  810.                      if (k == -1) break;
  811.                 }
  812.                 fkoff(SHELLPROG,SHELLOPTS,cmdbuf,NULL);
  813.                     /* source contents of .MANUAL file */
  814.             }
  815.             break;
  816.  
  817.  
  818.             default:            /* must be a topic spec */
  819.                 if ( no_subs )  {
  820.                 printf("\n Sorry, no subtopics.\n\n");
  821.                     break;
  822.             }
  823.             if ( (k = matchv( s1, topix, mx)) == 0 ) {
  824.                printf("\n Sorry, no help for %s.\n",s1);
  825.                printf(" (list cmnds with '*', topix with '#')\n");
  826.                break;    /* leave switch */
  827.             }
  828.  
  829. #ifdef DEBUG
  830.             fprintf(stderr,"diag: wvec= '%s' '%s' ...\n",
  831.                 wvec[0],(wvec[0]!=NULL)?(wvec[1]):NULL);
  832. #endif
  833.  
  834.                 for(i=0; i < k; i++) {
  835.                 s3 = mx[i];
  836.  
  837.                 if (i > 0) {
  838.                     j=takeit("\nNext %s subtopic: %s\nTake it?",
  839.                      ppt,s3);
  840.                 if (j ==  1) continue;
  841.                 if (j == -1) break;
  842.                 }
  843.  
  844.                 if ( chdir(s3) >= 0 ) {  /* directory  subtopic */
  845.                     strcpy(fullpath,ppt);
  846.                     strcat(fullpath," ");
  847.                     strcat(fullpath,s3);
  848.                     help1(fullpath,wvec,0);        /* recurse */
  849.                 if ( strcmp(getwd(newdir),helpdir) )
  850.                     chdir("..");
  851.                 }            /* else text subtopic */
  852.                 else  {
  853.                 strcpy(fullpath, ppt);
  854.                 strcat(fullpath, " ");
  855.                 strcat(fullpath, s3);
  856.                 printhelp(s3, fullpath);
  857.                 }
  858.             }
  859.  
  860.         }    /* end of switch */
  861.  
  862.     }    /* end of while(1) */
  863.  
  864.     if (!no_subs && (*topix != NULL) ) free( *topix );
  865.  
  866.     return(0);
  867.  
  868.   }    /* end of help1 */
  869.  
  870.  
  871. /* ****************************************************************
  872.  * takeit: ask user whether to take next topic, return t or f
  873.  *
  874.  *    This routine takes a message, with format, and asks the 
  875.  *  user whether he wants to do the action, not do the action,
  876.  *  or quit the cycle of actions.
  877.  *    y - return  0
  878.  *    n - return  1
  879.  *    q - return -1
  880.  *    ? - tell what y, n, and q do.
  881.  *      * - tell what y, n, and q do.
  882.  *     <CR> - carriage return
  883.  *
  884.  *    Naturally, case is insignificant.
  885.  */
  886.  
  887.  takeit(fmt,m1,m2,m3)
  888.    char *fmt, *m1, *m2, *m3;
  889.  {
  890.  
  891.     char ans[40];
  892.     int  done, ret;
  893.     char *fgets();
  894.  
  895.     for(done = 0; !done; ) {
  896.         if (fmt != NULL) printf(fmt, m1, m2, m3);
  897.         printf(" [ynq] ");
  898.         if (fgets(ans, 39, stdin) == NULL) exit(1);  /* abort */
  899.         isupper(*ans)?(*ans=tolower(*ans)):0;
  900.         if (*ans == 'n') {
  901.             done = 1;
  902.             ret = 1;
  903.         }
  904.         else if (*ans == 'y' || *ans == '\n') {
  905.             done = 1;
  906.             ret = 0;
  907.         }
  908.         else if (*ans == 'q') {
  909.             done = 1;
  910.             ret = -1;
  911.         }
  912.         else printf("  Answer y to get next subtopic, n to skip, q to quit.\n");
  913.     }
  914.     return(ret);
  915.  }
  916.  
  917.  
  918.  /* ***************************************************************
  919.   * matchv: return all matches of a string in a vector.
  920.   *
  921.   *    This routine accepts a string and a vector of strings. 
  922.   *  The string is supposed to be an abbreviation of one or more
  923.   *  strings in the vector.  The full versions of the strings are
  924.   *  placed in a another vector (which is in a static area) and
  925.   *  a pointer to that vector returned.  Note that the input
  926.   *  vector of pointers must have NULL as its terminating element.
  927.   *  The output vector will also terminate with NULL.
  928.   *    NOTE: The vector returned contains pointers into the input
  929.   *  vector.  Do not, therefore, mess with the contents of the output
  930.   *  vector.
  931.   *
  932.   *  If NULL is returned, nothing matched, or there was some other
  933.   *  error.
  934.   */
  935.  
  936.   matchv( src, vec, mx)
  937.     char *src;
  938.     char *vec[];
  939.     char *mx[];
  940.   {
  941.     char *m[MAXMATCHES];
  942.     char  *s1, *s2;
  943.     int i,j, slen;
  944.  
  945.     if ( (slen = strlen(src)) == 0 ) return(NULL);  
  946.  
  947.     for(i=0, j=0; vec[i] != NULL && j < MAXMATCHES; i++)
  948.         if ( strncmp(src,vec[i],slen) == 0   && 
  949.              strlen(vec[i]) >= slen )
  950.                    m[j++] = vec[i];
  951.     m[j] = NULL;
  952.     for(i=0; i <= j; mx[i] = m[i], i++);
  953.     return(j);
  954.   }
  955.  
  956.  /* *****************************************************************
  957.   * fkoff: fork a process and return the exit status of the process.
  958.   *
  959.   *    This routine takes a command line separated into words, and
  960.   *  uses vfork(2) and execve(2) to quickly run the program.
  961.   *
  962.   *  This is a simplified version of the fkoff() routine from dcon(8).
  963.   *  Here, a program name and up to four arguments may be passed in.
  964.   *  If one of them is null, FINE, but the fifth 
  965.   *
  966.   */
  967.  
  968.   fkoff(prg,arg1,arg2,arg3,arg4)
  969.     char *prg, *arg1, *arg2, *arg3, *arg4;
  970.  
  971.   {
  972.     char *command, *malloc(), *argvec[6];
  973.     int pid, stat, i;
  974.  
  975.     for(i=0; i < 6; argvec[i++] = NULL);
  976.     argvec[0] = prg;
  977.     argvec[1] = arg1;
  978.     argvec[2] = arg2;
  979.     argvec[3] = arg3;
  980.     argvec[4] = arg4;
  981.     if (argvec[0] == NULL) return(-1);
  982.     command = malloc( strlen(argvec[0]) + 1);
  983.     strcpy(command,argvec[0]);
  984.     
  985.     pid = vfork();    /* fork 2 copies of us */
  986.     if (pid == 0)  { /* we are child, execve the program. */
  987.            pid = execve(command,argvec,environ);
  988.         _exit(1);   
  989.     }
  990.     else {          /* we are parent, wait for child */
  991.         pid = wait(&stat);
  992.         if (pid == -1) return(pid);
  993.         stat = stat / 0400;   /* get hi byte of status */
  994.         return(stat);
  995.         }
  996.   }
  997.  
  998. /* **************************************************************
  999.  * makewvec: make a vector of words, up to 7 of them
  1000.  *
  1001.  *    This routine uses index to simply parse a string
  1002.  *  made up of (possibly) several blank-separated words.
  1003.  *  The words are stored into the slots of a vector, as pointers
  1004.  *  into the original string.  Therefore, the original string
  1005.  *  is destroyed.
  1006.  */
  1007.  makewvec(sstr, rvec)
  1008.      char *sstr;
  1009.      char *rvec[];
  1010. {
  1011.     int mcnt = 0;
  1012.     int done = 0;
  1013.     char *s1, *s2, *index();
  1014.  
  1015.     if (strlen(sstr) == 0) {
  1016.     rvec[0] = NULL;
  1017.     }
  1018.     else {
  1019.     /* skip leading whitespace */
  1020.     for(s1=sstr; iswhite(*s1); s1++);
  1021.     for(mcnt = 0, done = 0; !done; mcnt++) {
  1022.         s2 = index(s1,' ');
  1023.         if (s2 == NULL) s2 = index(s1,'    ');
  1024.         if (s2 == NULL) s2 = index(s1,'\n');
  1025.         if (s2 != NULL) *s2 = '\0';
  1026.         rvec[mcnt] = s1;
  1027.         if (s2 == NULL) done = 1;
  1028.         else {
  1029.         /* skip more white space */
  1030.         for(s1 = s2+1; iswhite(*s1); s1++);
  1031.         if (*s1 == '\0') done = 1;
  1032.         }
  1033.     }
  1034.     rvec[mcnt] = NULL;
  1035.     }
  1036.     return(mcnt);
  1037. }
  1038. SHAR_EOF
  1039. fi # end of overwriting check
  1040. #    End of shell archive
  1041. exit 0
  1042.  
  1043.